This document explains some of the compile and link errors you might see due to misuse of Exception and RTTI macros.
Table of Contents
-----------------
• Misuse of Exception Macros
• Misuse of RTTI Macros
Misuse of Exception Macros
Consider the following code:
class X
{
public:
FW_DECLARE_AUTO(X)
public:
X();
~X();
};
FW_DEFINE_AUTO(X)
X::X()
{
FW_END_CONSTRUCTOR
}
X::~X()
{
FW_START_DESTRUCTOR
}
void foo()
{
X x1;
}
The above code correctly uses the four required macros to make class X be an autodestruct class. In the examples that follow, we show the compile or link errors that appear if you "forget" or misuse one or more of the macros. The error messages are those emitted by Metrowerks Codewarrior, but other compilers will emit similar errors.
The FW_DECLARE_AUTO declares some functions that are defined by the FW_DEFINE_AUTO macro. If the FW_DECLARE_AUTO macro is omitted, the compiler will emit errors when the FW_DEFINE_AUTO macro is compiled.
2) You forget to use the FW_DEFINE_AUTO macro.
Link Error : undefined ‘X::operator delete(void*)’ (code)
Referenced from ‘X::~X()’ in Part.cpp
Link Error : undefined ‘FW_PrivGetDestroyProc(constX*)’ (code)
Referenced from ‘X::~X()’ in Part.cpp
Referenced from ‘X::X()’ in Part.cpp
Link Error : undefined ‘FW_PrivGetAutoName(constX*)’ (code)
Referenced from ‘X::~X()’ in Part.cpp
Referenced from ‘X::X()’ in Part.cpp
This is the reverse of case 1). Here, we assume the FW_DECLARE_AUTO macro is present, but the FW_DEFINE_AUTO macro is missing. In this case, some functions are declared, but never defined, so the error isn't detected until link time.
3) You forget to use both the FW_DECLARE_AUTO and FW_DEFINE_AUTO macros.
Link Error : undefined ‘FW_PrivGetDestroyProc<1X>(constX*)’ (code)
Referenced from ‘X::~X()’ in Part.cpp
Referenced from ‘X::X()’ in Part.cpp
Link Error : undefined ‘FW_PrivGetAutoName<1X>(constX*)’ (code)
Referenced from ‘X::~X()’ in Part.cpp
Referenced from ‘X::X()’ in Part.cpp
If you forget both the FW_DECLARE_AUTO and the FW_DEFINE_AUTO macros for a class, but then use the FW_END_CONSTRUCTOR and/or FW_START_DESTRUCTOR, you will get link errors like the above. These errors are not detected until link time because the two functions shown are declared as template functions, but the implementations for the templates are created only through the FW_DEFINE_AUTO macro.
4) You declare the FW_DECLARE_AUTO macro in a private section of your class.
This is a more subtle problem. Suppose you declared your class like this:
class X
{
FW_DECLARE_AUTO(X)
public:
X();
~X();
};
Since members of classes are private by default, the member functions defined by the FW_DECLARE_AUTO macro above will be private. This will result in errors like the following:
Error : illegal access to protected/private member
5) You forget to use FW_NEW when allocating new instances of your class.
Suppose that the function foo() above allocated an instance of class X using new, like this:
void foo()
{
X* x1 = new X;
}
Dynamically allocated autodestruct classes must be allocated with FW_NEW. If you forget and use the regular operator new instead, you'll get a compile time error:
Error : illegal access to protected/private member
Part.cpp line 130 X* x2 = new X();
This error happens because the FW_DECLARE_AUTO macro declares the standard operator new to be private.
6) You use the FW_NEW macro to create a nonautodestruct object.
Once you get in the habit of using FW_NEW, it's easy to make the mistake of using FW_NEW on a nonautodestruct class. For example, assume class Y is not an autodestruct class, and you write something like this:
void foo()
{
Y* y = FW_NEW(Y, ());
}
You should then see a compile error like this:
Error : function call '__nw(unsigned long, FW_CPrivWatcher)' does not match
'__nw(unsigned long)'
'__nw(unsigned long, void *)'
Part.cpp line 135 (Y*) ( new(FW_CPrivWatcher(FW_PrivGetDeleteProc((const Y*)0))) Y(), FW_PrivWatcher_Pop() )
This is because FW_NEW uses a overloaded variant of operator new that is only defined by the FW_DECLARE_AUTO macro.
7) You use FW_DEFINE_AUTO twice for the same class.
Sometimes it's convient to create a new class by copying code from another class and then renaming. If you do this by hand and forget to rename the class in the FW_DEFINE_AUTO macro, you'll be invoking the FW_DEFINE_AUTO macro twice for the same class. This will show up as a compile time error if both instances of the macro are in the same .cpp file, or as a link-time error if they are in separate .cpp files.
8) You use FW_DEFINE_AUTO where FW_DECLARE_AUTO should be used.
Suppose you use the FW_DEFINE_AUTO macro in the class declaration by mistake. This will cause a whole series of errors, beginning with these:
The above code correctly uses the FW_DECLARE_CLASS and FW_DEFINE_CLASS_Mn macros required to make classes have runtime type identification. In the examples that follow, we show the compile or link errors that appear if you forget or misuse one or more of the macros. The error messages are those emitted by Metrowerks Codewarrior, but other compilers will emit similar errors.
1) You forget to use the FW_DECLARE_CLASS macro.
Suppose you left out the FW_DECLARE_CLASS macro for class A. You'd then get these compile-time errors:
Error : 'gAncestors' is not a struct/union/class member
Error : 'PrivVirtualGetClassInfo' is not a struct/union/class member
Part.cpp line 1
The FW_DECLARE_CLASS macro declares some static data members and a virtual function. If you forget the FW_DECLARE_CLASS macro but use the FW_DEFINE_CLASS_Mn macro, the compiler emit errors for the references to undeclared data and functions.
2) You forget to use the FW_DEFINE_CLASS_Mn macro.
Suppose you left out the FW_DEFINE_CLASS_M0 macro for class A. You'd then get the following link-time errors:
Link Error : undefined ‘A::gClassInfo’ (data)
Referenced from ‘FW_PrivStaticGetClassInfo<1A>(A*)’ in Part.cpp
Referenced from ‘B::gAncestors’ in Part.cpp
Link Error : missing vtable ‘A::__vt’
Check that all virtual functions and static members are defined
In this case, the members are declared but never defined (implemented), so the error doesn't show up until link time. Note in particular the last link error. Many C++ compilers generate the vtable for a class in the translation unit that implements the first virtual function declared for the class. Since by convention, we normally place the FW_DECLARE_CLASS macro at the top of the class declaration, the virtual function declared by the FW_DECLARE_CLASS macro is the first virtual function. Since it isn't implemented, the compiler doesn't generate the vtable; hence the error "missing vtable ‘A::__vt’".